/****************************************************************
 * Nombre: Iterador.java 
 * Versión: 1.0.0 
 * Autor: Alberto de Jesús Castro Becerra, Alonso Fabián Orozco Pérez	
 * Creado: 1-abril-2013 
 * Modificado: 02-abril-2013 
 * Diagrama: GAPI v4.6.1 
 * Caso de uso: MGH1 
 ****************************************************************/
package Servicios;

import Dominio.AsignaturaOfertaAcademicaPonderada;
import Dominio.OpcionHorario;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * Implementación de <code>Iterable</code> para recorrer opciones de horario.
 * @author Alberto
 */
public class Iterador implements Iterable<OpcionHorario> {

    private ArrayList<AsignaturaOfertaAcademicaPonderada> lista;
    private Integer k;

    /**
     * Constructor de la clase.
     * @param s Lista de asignaturas ponderadas de la oferta académica.
     * @param k Número de asignaturas a considerar por opción de horario.
     */
    public Iterador(ArrayList<AsignaturaOfertaAcademicaPonderada> s, Integer k) {
        lista = s;
        this.k = k;
    }
    /**
     * Devuelve una instancia de IterdorCombinacion.
     * @return Instancia de IteradorCombinacion
     */
    @Override
    public Iterator<OpcionHorario> iterator() {
        return new IteradorCombinacion(lista, k);
    }

    /**
     * Inner class que implementa la infertaz <code>Iterator</code> sobre OpcionHorario.
     */
    class IteradorCombinacion implements Iterator<OpcionHorario> {

        private int actualSize, maxresult;
        private Integer curIndex;
        private AsignaturaOfertaAcademicaPonderada[] result;
        private int[] indices;
        private AsignaturaOfertaAcademicaPonderada[] arrayList;
        private OpcionHorario elem = null;

        /**
         * Constructor de la clase.
         * @param s ArrayList de asignaturas ponderadas de la oferta académica.
         * @param k 
         */
        public IteradorCombinacion(ArrayList<AsignaturaOfertaAcademicaPonderada> s, Integer k) {
            actualSize = k;// desde dónde
            curIndex = 0;
            maxresult = k;
            arrayList = new AsignaturaOfertaAcademicaPonderada[s.size()];
            for (int i = 0; i < arrayList.length; i++) { // la lista s la vuelca en arrayList
                arrayList[i] = s.get(i);
            }
            this.result = new AsignaturaOfertaAcademicaPonderada[actualSize < s.size() ? actualSize : s.size()];
            //el tamaño de result va a ser el valor menor entre actualSize y el tamaño de s
            indices = new int[result.length];

            for (int i = 0; i < result.length; i++) {
                indices[i] = result.length - 2 - i;
            }
        }

        /**
         * Determina si la colección tiene un siguiente elemento.
         * @return True si hay otro elemento, false en caso contrario.
         */
        public boolean hasNext() {
            elem = null;
            while ((elem == null && curIndex != -1)) {

                indices[curIndex]++;
                if (indices[curIndex] == (curIndex == 0 ? arrayList.length : indices[curIndex - 1])) {

                    indices[curIndex] = indices.length - curIndex - 2;
                    curIndex--;
                } else {

                    result[curIndex] = arrayList[indices[curIndex]];

                    if (curIndex < indices.length - 1) {
                        curIndex++;
                    } else {
                        elem = new OpcionHorario(); 
                        for (AsignaturaOfertaAcademicaPonderada s : result) {
                            elem.agregarAsignaturaPonderada(s);

                        }
                    }
                }
            }

            if (elem == null) {
                if (actualSize < maxresult) {
                    actualSize++;
                    this.result = new AsignaturaOfertaAcademicaPonderada[actualSize < arrayList.length ? actualSize : arrayList.length];
                    indices = new int[result.length];

                    for (int i = 0; i < result.length; i++) {

                        indices[i] = result.length - 2 - i;
                    }
                    curIndex = 0;

                    return this.hasNext();
                } else {
                    return false;
                }
            } else {
                return true;
            }
        }

        @Override
        public OpcionHorario next() {
            return elem;
        }

        @Override
        public void remove() {
        }
    }
}
